{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Creating a basic chat experience with context variables\n",
    "\n",
    "In this example, we show how you can build a simple chat bot by sending and updating context with your requests. \n",
    "\n",
    "We introduce the Context Variables object which in this demo functions similarly as a key-value store that you can use when running the kernel.\n",
    "\n",
    "The context is local (i.e. in your computer's RAM) and not persisted anywhere beyond the life of this Jupyter session.\n",
    "\n",
    "In future examples, we will show how to persist the context on disk so that you can bring it into your applications.  \n",
    "\n",
    "In this chat scenario, as the user talks back and forth with the bot, the context gets populated with the history of the conversation. During each new run of the kernel, the context can provide the AI with its variables' content. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "#r \"nuget: Microsoft.SemanticKernel, 0.12.207.1-preview\"\n",
    "\n",
    "#!import config/Settings.cs\n",
    "\n",
    "using Microsoft.SemanticKernel;\n",
    "using Microsoft.SemanticKernel.SemanticFunctions;\n",
    "using Microsoft.SemanticKernel.Orchestration;\n",
    "\n",
    "IKernel kernel = KernelBuilder.Create();\n",
    "\n",
    "// Configure AI backend used by the kernel\n",
    "var (useAzureOpenAI, model, azureEndpoint, apiKey, orgId) = Settings.LoadFromFile();\n",
    "if (useAzureOpenAI)\n",
    "    kernel.Config.AddAzureTextCompletionService(\"davinci\", model, azureEndpoint, apiKey);\n",
    "else\n",
    "    kernel.Config.AddOpenAITextCompletionService(\"davinci\", model, apiKey, orgId);"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's define a prompt outlining a dialogue chat bot."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "const string skPrompt = @\"\n",
    "ChatBot can have a conversation with you about any topic.\n",
    "It can give explicit instructions or say 'I don't know' if it does not have an answer.\n",
    "\n",
    "{{$history}}\n",
    "Human: {{$human_input}}\n",
    "ChatBot:\";\n",
    "\n",
    "var promptConfig = new PromptTemplateConfig\n",
    "{\n",
    "    Completion =\n",
    "    {\n",
    "        MaxTokens = 2000,\n",
    "        Temperature = 0.7,\n",
    "        TopP = 0.5,\n",
    "    }\n",
    "};"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Register your semantic function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "var promptTemplate = new PromptTemplate(skPrompt, promptConfig, kernel);\n",
    "var functionConfig = new SemanticFunctionConfig(promptConfig, promptTemplate);\n",
    "var chatFunction = kernel.RegisterSemanticFunction(\"ChatBot\", \"Chat\", functionConfig);"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Initialize your context"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "var context = new ContextVariables();\n",
    "\n",
    "var history = \"\";\n",
    "context.Set(\"history\", history);"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Chat with the Bot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "var human_input = \"Hi, I'm looking for book suggestions\";\n",
    "context.Set(\"human_input\", human_input);\n",
    "\n",
    "var bot_answer = await kernel.RunAsync(context, chatFunction);"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Update the history with the output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Human: Hi, I'm looking for book suggestions\n",
      "Melody:  Hi there! What kind of books are you looking for?\n",
      "\n"
     ]
    }
   ],
   "source": [
    "history += $\"\\nHuman: {human_input}\\nMelody: {bot_answer}\\n\";\n",
    "context.Update(history);\n",
    "\n",
    "Console.WriteLine(context);"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Keep Chatting!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [],
   "source": [
    "Func<string, Task> Chat = async (string input) => {\n",
    "    // Save new message in the context variables\n",
    "    context.Set(\"human_input\", input);\n",
    "\n",
    "    // Process the user message and get an answer\n",
    "    var answer = await kernel.RunAsync(context, chatFunction);\n",
    "\n",
    "    // Append the new interaction to the chat history\n",
    "    history += $\"\\nHuman: {input}\\nMelody: {answer}\\n\"; context.Set(\"history\", history);\n",
    "    \n",
    "    // Show the response\n",
    "    Console.WriteLine(context);\n",
    "};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " The Landmark Thucydides: A Comprehensive Guide to the Peloponnesian War by Robert B. Strassler is a great book to learn about the history of Greece.\n"
     ]
    }
   ],
   "source": [
    "await Chat(\"I would like a non-fiction book suggestion about Greece history. Please only list one book.\");"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " The Landmark Thucydides covers topics such as the causes of the Peloponnesian War, the strategies and tactics used by the Greeks and Persians, the roles of Athens and Sparta, and the impact of the war on the Greek world.\n"
     ]
    }
   ],
   "source": [
    "await Chat(\"that sounds interesting, what are some of the topics I will learn about?\");"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " Most people find the strategies and tactics used by the Greeks and Persians to be the most interesting topic in The Landmark Thucydides.\n"
     ]
    }
   ],
   "source": [
    "await Chat(\"Which topic from the ones you listed do you think most people find interesting?\");"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "dotnet_interactive": {
     "language": "csharp"
    },
    "polyglot_notebook": {
     "kernelName": "csharp"
    },
    "vscode": {
     "languageId": "polyglot-notebook"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " Most people find the strategies and tactics used by the Greeks and Persians to be the most interesting topic in The Landmark Thucydides.\n"
     ]
    }
   ],
   "source": [
    "await Chat(\"could you list some more books I could read about the topic(s) you mentioned?\");"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".NET (C#)",
   "language": "C#",
   "name": ".net-csharp"
  },
  "language_info": {
   "file_extension": ".cs",
   "mimetype": "text/x-csharp",
   "name": "C#",
   "pygments_lexer": "csharp",
   "version": "11.0"
  },
  "polyglot_notebook": {
   "kernelInfo": {
    "defaultKernelName": "csharp",
    "items": [
     {
      "aliases": [],
      "name": "csharp"
     }
    ]
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
